{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "source": [
    "# Plotting traces (collections)\n",
    "This Tutorial explains how to customize network plots in pandapower using plotly. Each pandapower network element can be translated into a plotly trace with all corresponding properties."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-26T11:20:31.842639Z",
     "start_time": "2025-11-26T11:20:26.800990Z"
    }
   },
   "outputs": [],
   "source": [
    "from pandapower.create import (\n",
    "    create_empty_network,\n",
    "    create_bus,\n",
    "    create_line,\n",
    "    create_transformer3w,\n",
    "    create_transformer,\n",
    "    create_ext_grid,\n",
    "    create_load,\n",
    ")\n",
    "import pandapower.networks as nw\n",
    "import pandapower.plotting.plotly as pplotly\n",
    "from pandas import Series\n",
    "import numpy as np\n",
    "\n",
    "# Prevent Dark Background on plots\n",
    "import plotly.io as pio\n",
    "pio.templates.default = \"plotly_white\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We created a network along with geodata in the buses."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-26T11:20:32.045746Z",
     "start_time": "2025-11-26T11:20:31.851890Z"
    }
   },
   "outputs": [],
   "source": [
    "net = create_empty_network()\n",
    "x = np.array([0, -2, 2, -3, -2, 2])\n",
    "y = np.array([4, 3, 3, -3, -2, -2])\n",
    "for i in range(6):\n",
    "    if i < 3:\n",
    "        v = 110\n",
    "    elif i == 3:\n",
    "        v = 20\n",
    "    else:\n",
    "        v = 10\n",
    "    create_bus(net, vn_kv=v, geodata=(x[i], y[i]))\n",
    "\n",
    "create_line(net, 0, 1, 5, \"149-AL1/24-ST1A 110.0\", geodata=None, name=\"l1\")\n",
    "create_line(net, 0, 2, 5, \"149-AL1/24-ST1A 110.0\", geodata=None, name=\"l2\")\n",
    "create_transformer3w(net, 1, 3, 4, \"63/25/38 MVA 110/20/10 kV\", name=\"tr1\")\n",
    "\n",
    "create_transformer(net, 2, 5, \"0.25 MVA 20/0.4 kV\", name=\"tr2\")\n",
    "\n",
    "create_ext_grid(net, 0)\n",
    "create_load(net, 4, p_mw=20.0, q_mvar=10.0, name=\"load1\")\n",
    "create_load(net, 5, p_mw=20.0, q_mvar=10.0, name=\"load1\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If you want to have full control over the layout of your plot, you can individually create and plot collections with the pandapower plotting module."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-26T11:20:33.645802Z",
     "start_time": "2025-11-26T11:20:32.055753Z"
    },
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "lc = pplotly.create_line_trace(net, net.line.index, color=\"black\", infofunc=net.line.name)\n",
    "bc = pplotly.create_bus_trace(net, net.bus.index, size=10, color=\"orange\", infofunc=net.bus.vn_kv)\n",
    "tc3 = pplotly.create_trafo_trace(\n",
    "    net,\n",
    "    net.trafo3w.index,\n",
    "    trafotype=\"3W\",\n",
    "    color=\"green\",\n",
    "    infofunc=net.trafo3w.name,\n",
    "    trace_name=\"trafo3ws\",\n",
    "    cmin=None,\n",
    "    cmax=None,\n",
    "    cmap_vals=None,\n",
    "    use_line_geo=None,\n",
    ")\n",
    "tc = pplotly.create_trafo_trace(\n",
    "    net,\n",
    "    net.trafo.index,\n",
    "    trafotype=\"2W\",\n",
    "    color=\"blue\",\n",
    "    infofunc=net.trafo.name,\n",
    "    trace_name=\"trafos\",\n",
    "    cmin=None,\n",
    "    cmax=None,\n",
    "    cmap_vals=None,\n",
    "    use_line_geo=None,\n",
    ")\n",
    "_ = pplotly.draw_traces(bc + lc + tc + tc3, figsize=1, aspectratio=(8, 4));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-26T11:20:37.543880Z",
     "start_time": "2025-11-26T11:20:33.966953Z"
    }
   },
   "outputs": [],
   "source": [
    "net = nw.mv_oberrhein()\n",
    "\n",
    "lc = pplotly.create_line_trace(net, net.line.index, color=\"black\")\n",
    "bc = pplotly.create_bus_trace(\n",
    "    net,\n",
    "    net.bus.index,\n",
    "    size=10,\n",
    "    color=\"orange\",\n",
    "    infofunc=Series(index=net.bus.index, data=net.bus.name + \"<br>\" + net.bus.vn_kv.astype(str) + \" kV\"),\n",
    ")\n",
    "pplotly.draw_traces(bc + lc, figsize=1, aspectratio=(8, 6));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Order of plotting traces is as ordered in the `draw_traces` function. So, in order to plot buses in front of lines first lines and then buses need to be set in the input traces list:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-26T11:20:38.035214Z",
     "start_time": "2025-11-26T11:20:37.788856Z"
    }
   },
   "outputs": [],
   "source": [
    "pplotly.draw_traces(lc + bc, figsize=1, aspectratio=(8, 6));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Highlighting\n",
    "Specific lines or buses can be highlighted by creating extra line collections in different colors.\n",
    "\n",
    "In this example, we plot lines that are longer than 2 km green and buses with a voltage below 0.98 p.u. red.\n",
    "\n",
    "First, we create a line collection for all lines in grey and a line collection for only the long lines in green:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-26T11:20:39.804905Z",
     "start_time": "2025-11-26T11:20:38.478010Z"
    }
   },
   "outputs": [],
   "source": [
    "long_lines = net.line[net.line.length_km > 2.0].index\n",
    "lc = pplotly.create_line_trace(net, net.line.index, color=\"grey\")\n",
    "lcl = pplotly.create_line_trace(\n",
    "    net,\n",
    "    long_lines,\n",
    "    color=\"green\",\n",
    "    width=2,\n",
    "    infofunc=Series(\n",
    "        index=net.line.index,\n",
    "        data=net.line.name[long_lines] + \"<br>\" + net.line.length_km[long_lines].astype(str) + \" km\",\n",
    "    ),\n",
    ")\n",
    "\n",
    "low_voltage_buses = net.res_bus[net.res_bus.vm_pu < 0.98].index\n",
    "bc = pplotly.create_bus_trace(net, net.bus.index, size=10, color=\"blue\")\n",
    "bch = pplotly.create_bus_trace(net, low_voltage_buses, size=10, color=\"red\")\n",
    "\n",
    "pplotly.draw_traces(bc + bch + lc + lcl);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "source": [
    "## Highlighting with the Topology Package\n",
    "Colors palette for plotly can be obtained using function `plotting.plotly.get_plotly_color_palette(n)` where argument `n` defines number of colors that will be returned in a list."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-26T11:20:41.377690Z",
     "start_time": "2025-11-26T11:20:40.081365Z"
    }
   },
   "outputs": [],
   "source": [
    "from pandapower.plotting.plotly import get_plotly_color_palette\n",
    "from pandapower.topology import create_nxgraph, connected_components\n",
    "\n",
    "net = nw.mv_oberrhein()\n",
    "\n",
    "mg = create_nxgraph(net, nogobuses=set(net.trafo.lv_bus.values) | set(net.trafo.hv_bus.values))\n",
    "collections = []\n",
    "ai = 0\n",
    "islands = list(connected_components(mg))  # getting connected components of a graph\n",
    "colors = get_plotly_color_palette(len(islands))  # getting a color for each connected component\n",
    "for color, area in zip(colors, islands):\n",
    "    collections += pplotly.create_bus_trace(net, area, size=5, color=color, trace_name=\"feeder {0}\".format(ai))\n",
    "    ai += 1\n",
    "collections += pplotly.create_line_trace(net, net.line.index, color=\"grey\")\n",
    "collections += pplotly.create_bus_trace(net, net.ext_grid.bus.values, patch_type=\"square\", size=10, color=\"yellow\")\n",
    "pplotly.draw_traces(collections);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Collection on mapbox\n",
    "Plots on Mapbox maps are available only considering you have a Mapbox account and a Mapbox Access Token. After getting a mabox token it can be written set to pandapower as the following (where `'<token>'` needs to be replaced with provided mapbox token).\n",
    "If network geo-data are not in lat/long form, there is a function `geo_data_to_latlong` which can be used to transform entire network geodata from a specific projection to lat/long:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-26T11:20:43.441138Z",
     "start_time": "2025-11-26T11:20:41.656355Z"
    }
   },
   "outputs": [],
   "source": [
    "net = nw.mv_oberrhein()\n",
    "# convert_crs(net, epsg_out=31467) #transforming geodata to Gauß Krüger Zone 3\n",
    "\n",
    "lc = pplotly.create_line_trace(net, net.line.index, color=\"purple\")\n",
    "bc = pplotly.create_bus_trace(\n",
    "    net,\n",
    "    net.bus.index,\n",
    "    size=10,\n",
    "    color=\"orange\",\n",
    "    infofunc=Series(index=net.bus.index, data=net.bus.name + \"<br>\" + net.bus.vn_kv.astype(str) + \" kV\"),\n",
    ")\n",
    "_ = pplotly.draw_traces(lc + bc, on_map=True, map_style=\"dark\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Colormaps\n",
    "Colormaps plots are available for plotly by setting `cmap=True` in create functions. By default, line loading and bus voltage magnitudes will be used for coloring."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-26T11:20:44.769454Z",
     "start_time": "2025-11-26T11:20:43.669112Z"
    }
   },
   "outputs": [],
   "source": [
    "net = nw.mv_oberrhein()\n",
    "bt = pplotly.create_bus_trace(net, cmap=True)\n",
    "lt = pplotly.create_line_trace(net, cmap=True)\n",
    "pplotly.draw_traces(lt + bt, showlegend=False);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Some customization is possible in regard to: limits, choosing a colormap, colorbar title, etc."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-26T11:20:45.368409Z",
     "start_time": "2025-11-26T11:20:45.093158Z"
    }
   },
   "outputs": [],
   "source": [
    "lt = pplotly.create_line_trace(net, cmap=\"Blues\", cmin=0, cmax=100, cbar_title=\"Line loading [%]\")\n",
    "pplotly.draw_traces(lt, showlegend=False);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Alternatively, any other values can be used for colormaps, with also some customization in regard to limits, choosing a colormap, colorbar title, etc. An example with coloring according to line length:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-26T11:20:45.989452Z",
     "start_time": "2025-11-26T11:20:45.578423Z"
    }
   },
   "outputs": [],
   "source": [
    "lt = pplotly.create_line_trace(net, cmap_vals=net.line.length_km, cmap=True, cbar_title=\"Line length [km]\")\n",
    "pplotly.draw_traces(lt, showlegend=False);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Customized hover-info\n",
    "Information that pop-ups when a bus or a line is pointed with mouse-cursor is called hover-info. By default, it is set to bus/line name, but it can be customized by setting a list of strings to `infofunc` argument. A newline is defined using `<br>`. See a representative example hereafter (try getting hoverinfo by pointing a cursor above each bus):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-26T11:20:46.381044Z",
     "start_time": "2025-11-26T11:20:46.196803Z"
    }
   },
   "outputs": [],
   "source": [
    "bc = pplotly.create_bus_trace(\n",
    "    net,\n",
    "    [1, 2, 3, 4, 5],\n",
    "    size=15,\n",
    "    infofunc=Series(\n",
    "        index=net.bus.index,\n",
    "        data=net.bus.name + \"<br>\" + net.bus.vn_kv.astype(str) + \" kV\" + \"<br>\" + \"this is one of the 5 buses...\",\n",
    "    ),\n",
    ")\n",
    "pplotly.draw_traces(bc);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Weighted Marker Traces\n",
    "A trace with markers of value-dependent size can be created by the `create_weighted_marker_trace` function. Like other traces, this trace can be passed to `draw_traces` directly, or it can be passed as \"additional trace\" to `simple_plotly`. By default, the latter will also add a reference marker to indicate the value for one size."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-26T11:20:47.224355Z",
     "start_time": "2025-11-26T11:20:46.694026Z"
    }
   },
   "outputs": [],
   "source": [
    "net.sgen.scaling = 1\n",
    "marker_trace = pplotly.create_weighted_marker_trace(\n",
    "    net, \"sgen\", column_to_plot=\"p_mw\", marker_scaling=200, color=\"green\", patch_type=\"circle-open\"\n",
    ")\n",
    "_ = pplotly.simple_plotly(net, bus_size=0.25, additional_traces=[marker_trace])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-26T11:20:47.930266Z",
     "start_time": "2025-11-26T11:20:47.405120Z"
    }
   },
   "outputs": [],
   "source": [
    "marker_trace = pplotly.create_weighted_marker_trace(\n",
    "    net, \"sgen\", column_to_plot=\"p_mw\", marker_scaling=400, color=\"green\", patch_type=\"circle-open\", show_scale_legend=True, scale_legend_unit='MW', scale_marker_size=[0., 1, 2, 5]\n",
    ")\n",
    "pplotly.simple_plotly(net, bus_size=0.25, additional_traces=[marker_trace]);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "More tutorials about interactive plots using plotly:\n",
    "* [built-in interactive plots](./plotly_built-in.ipynb)\n",
    "* [interactive plots on maps](./plotly_maps.ipynb)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
